//      explorer.c
//      
//      Copyright 2011 DJ Shaji <djshaji@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.


#include "explorer.h"

Explorer * explorer_new ( void )
{
	GMemChunk * mem = g_mem_chunk_create ( Explorer, 10, G_ALLOC_ONLY ) ;
	Explorer * explorer = g_chunk_new ( Explorer, mem ) ;
	
	explorer_nullify_variables ( explorer ) ;
	
	explorer -> mem = mem ;
	explorer -> window = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
	
	g_signal_connect_after ( explorer -> window, "key-press-event", hotkeys, explorer ) ;
	g_signal_connect_swapped ( explorer -> window, "destroy", explorer_destroy, explorer ) ;
	
	explorer -> pack = gtk_vbox_new ( no, 0 ) ;
	gtk_container_add ( explorer -> window, explorer -> pack ) ;
	
	explorer -> menubar = gtk_menu_bar_new () ;
	gtk_box_pack_start ( explorer -> pack, explorer -> menubar, no, no, 2 ) ;
	
	gtk_box_pack_start ( explorer -> pack, gtk_hseparator_new (), no, no, 2 ) ;
	
	explorer -> toolbar = gtk_toolbar_new () ;
	gtk_box_pack_start ( explorer -> pack, explorer -> toolbar, no, no, 2 ) ;
	
	gtk_toolbar_set_icon_size ( explorer -> toolbar, GTK_ICON_SIZE_LARGE_TOOLBAR ) ;
	gtk_toolbar_set_style ( explorer -> toolbar, GTK_TOOLBAR_BOTH ) ;
	
	explorer -> statusbar = gtk_statusbar_new () ;
	
	explorer_create_toolbar ( explorer ) ;
	explorer_create_menubar ( explorer ) ;

	gtk_box_pack_start ( explorer -> pack, gtk_hseparator_new (), no, no, 2 ) ;
	
	explorer -> addressbar = gtk_hbox_new ( no, 0 ) ;
	explorer_create_addressbar ( explorer ) ;
	
	gtk_box_pack_start ( explorer -> pack, explorer -> addressbar, no, no, 2 ) ;
	gtk_box_pack_start ( explorer -> pack, gtk_hseparator_new (), no, no, 2 ) ;
	
	explorer -> iconbox = gtk_vbox_new ( no, 0 ) ;
	gtk_box_pack_start ( explorer -> pack, explorer -> iconbox, yes, yes, 0 ) ;
	
	GtkScrolledWindow * sw = gtk_scrolled_window_new ( null, null ) ;
	
	gtk_scrolled_window_set_policy ( sw, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ) ;
	
	explorer -> iconview = gtk_icon_view_new () ;
	gtk_box_pack_start ( explorer -> iconbox, sw, yes, yes, 0 ) ;
	
	gtk_icon_view_set_pixbuf_column ( explorer -> iconview, 0 ) ;
	gtk_icon_view_set_text_column ( explorer -> iconview, 1 ) ;
	
	gtk_icon_view_set_item_width ( explorer -> iconview, 80 ) ;
	gtk_icon_view_set_row_spacing ( explorer -> iconview, 1 ) ;
	
	gtk_icon_view_set_selection_mode ( explorer -> iconview, GTK_SELECTION_MULTIPLE ) ;
	
	g_signal_connect ( explorer -> iconview, "item-activated", fm_icon_view_activated, explorer ) ;
	g_signal_connect ( explorer -> iconview, "button-press-event", fm_handle_context_menu, explorer ) ;
	
	gtk_container_add ( sw, explorer -> iconview ) ;

	explorer -> store = fm_create_store () ;
	gtk_icon_view_set_model ( explorer -> iconview, explorer -> store ) ;
	
	gtk_box_pack_start ( explorer -> pack, explorer -> statusbar, no, no, 0 ) ;
	
	gtk_window_resize ( explorer -> window, 580, 400 ) ;
	gtk_widget_grab_focus ( explorer -> iconview ) ;
	
	gtk_widget_show_all ( explorer -> window ) ;
	return explorer ;
}

void explorer_create_menubar ( Explorer * e )
{
	GtkMenuItem * file = gtk_menu_item_new_with_label ( "File" ),
				* edit = gtk_menu_item_new_with_label ( "Edit" ),
				* view = gtk_menu_item_new_with_label ( "View" ),
				* go = gtk_menu_item_new_with_label ( "Go" ),
				* f = gtk_menu_item_new_with_label ( "Favorites" ),
				* help = gtk_menu_item_new_with_label ( "Help" ) ;
	
	e -> f_item = f ;
	
	gtk_menu_item_set_submenu ( file, fm_create_menu_file ( e )) ;
	gtk_menu_item_set_submenu ( edit, fm_create_menu_edit ( e )) ;
	gtk_menu_item_set_submenu ( view, fm_create_menu_view ( e )) ;
	gtk_menu_item_set_submenu ( go, fm_create_menu_go ( e )) ;
	gtk_menu_item_set_submenu ( f, fm_create_menu_favorites ( e )) ;
	gtk_menu_item_set_submenu ( help, fm_create_menu_help ( e )) ;

	gtk_menu_shell_append ( e -> menubar, file ) ;
	gtk_menu_shell_append ( e -> menubar, edit ) ;
	
	gtk_menu_shell_append ( e -> menubar, view ) ;
	gtk_menu_shell_append ( e -> menubar, go ) ;
	
	gtk_menu_shell_append ( e -> menubar, f ) ;
	gtk_menu_shell_append ( e -> menubar, help ) ;
	
	gtk_widget_show_all ( e -> menubar ) ;
}

void explorer_create_toolbar ( Explorer * e )
{
	GtkToolButton * back = gtk_tool_button_new_from_stock ( "gtk-go-back" ),
//				  * h1 = gtk_tool_button_new ( gtk_arrow_new ( GTK_ARROW_DOWN, GTK_SHADOW_OUT ), null ),
				  * next = gtk_tool_button_new_from_stock ( "gtk-go-forward" ),
				  * up = gtk_tool_button_new_from_stock ( "gtk-go-up" ),
//				  * h2 = gtk_tool_button_new ( gtk_arrow_new ( GTK_ARROW_DOWN, GTK_SHADOW_OUT ), null ),
				  * cut = gtk_tool_button_new_from_stock ( "gtk-cut" ),
				  * copy = gtk_tool_button_new_from_stock ( "gtk-copy" ),
				  * paste = gtk_tool_button_new_from_stock ( "gtk-paste" ) ;
				  //* undo = gtk_tool_button_new_from_stock ( "gtk-undo" ) ;
				  
	
	GError * error = null ;
	e -> anim = gtk_tool_item_new () ;
	
	e -> anim_p = gdk_pixbuf_animation_new_from_file ( WAIT_ANIMATION, & error ) ;
	if ( error )
	{
		g_critical ( "Cannot load image: %s", error -> message ) ;
	}
	
	else
	{
		GtkImage * image = gtk_image_new_from_animation ( e -> anim_p ) ;
		gtk_container_add ( e -> anim, image ) ;
	}
	
	// I don't think we'll need this anymore
	g_object_unref ( e -> anim_p ) ;
	
	g_signal_connect_swapped ( back, "clicked", fm_go_back, e ) ;
	g_signal_connect_swapped ( next, "clicked", fm_go_forward, e ) ;
	
	g_signal_connect_swapped ( up, "clicked", fm_go_up, e ) ;
	
	g_signal_connect_swapped ( cut, "clicked", explorer_cut_callback, e ) ;
	g_signal_connect_swapped ( copy, "clicked", explorer_copy_callback, e ) ;
	
	g_signal_connect_swapped ( paste, "clicked", explorer_paste_from_clipboard, e ) ;
	
//	gtk_tool_item_set_expand ( h1, no ) ;
//	gtk_tool_item_set_homogeneous ( h1, no ) ;
	
//	gtk_tool_item_set_expand ( h2, no ) ;
//	gtk_tool_item_set_homogeneous ( h2, no ) ;
	
	gtk_toolbar_insert ( e -> toolbar, back, -1 ) ;
	//gtk_toolbar_insert ( e -> toolbar, h1, -1 ) ;
	
	gtk_toolbar_insert ( e -> toolbar, next, -1 ) ;
	//gtk_toolbar_insert ( e -> toolbar, h2, -1 ) ;
	
	gtk_toolbar_insert ( e -> toolbar, up, -1 ) ;
	gtk_toolbar_insert ( e -> toolbar, gtk_separator_tool_item_new (), -1 ) ;
	
	gtk_toolbar_insert ( e -> toolbar, cut, -1 ) ;
	
	gtk_toolbar_insert ( e -> toolbar, copy, -1 ) ;
	gtk_toolbar_insert ( e -> toolbar, paste, -1 ) ;
	
	GtkSeparatorToolItem * s = gtk_separator_tool_item_new () ;
	gtk_tool_item_set_expand ( s, yes ) ;
	
	gtk_toolbar_insert ( e -> toolbar, s, -1 ) ;
	gtk_separator_tool_item_set_draw ( s, no ) ;
	
	gtk_toolbar_insert ( e -> toolbar, e -> anim, -1 ) ;
	gtk_widget_show_all ( e -> toolbar ) ;
	
	/*
	gtk_toolbar_insert ( e -> toolbar, gtk_separator_tool_item_new (), -1 ) ;
	gtk_toolbar_insert ( e -> toolbar, undo, -1 ) ;
	*/
}


void explorer_create_addressbar ( Explorer * e )
{
	GtkLabel * l = gtk_label_new ( "Address" ) ;
	e -> addressbar_entry = gtk_combo_box_entry_new_text () ;
	
	g_signal_connect ( gtk_bin_get_child ( e -> addressbar_entry ), "activate", explorer_addressbar_activated, e ) ;
	
	gtk_box_pack_start ( e -> addressbar, l, no, no, 2 ) ;
	gtk_box_pack_start ( e -> addressbar, e -> addressbar_entry, yes, yes, 2 ) ;
}

void explorer_new_instance ( gchar * folder )
{
	Explorer * e = explorer_new () ;
	
	if ( folder )
		fm_open ( e, folder ) ;
	else
		fm_open ( e, g_get_home_dir ()) ;
}

void explorer_set_status_message ( Explorer * e, gchar * message )
{
	gtk_statusbar_push ( e -> statusbar,
						gtk_statusbar_get_context_id ( e -> statusbar, message ),
						message ) ;
}

void explorer_nullify_variables ( Explorer * e )
{
	/* This function is more important than you might think */
	
	e -> counter = 0 ;
	e -> timestamp = 0 ;
	
	e -> history_back = gtk_list_store_new ( 1, G_TYPE_STRING ) ;
	e -> history_forward = gtk_list_store_new ( 1, G_TYPE_STRING ) ;
	
	e -> clipboard = gtk_clipboard_get ( GDK_NONE ) ;
	
	e -> store = null ;
	e -> config.click_mode = 2 ;
}

gchar * explorer_get_current_folder ( Explorer * e )
{
	return gtk_combo_box_get_active_text ( e -> addressbar_entry ) ;
}

void explorer_wait_anim_start ( Explorer * e )
{
	gtk_widget_show ( e -> anim ) ;
}

void explorer_wait_anim_stop ( Explorer * e )
{
	gtk_widget_hide ( e -> anim ) ;
}

void explorer_addressbar_activated ( GtkWidget * entry, Explorer * e )
{
	gchar * folder = explorer_get_current_folder ( e ) ;
	fm_open ( e, folder ) ;
	
	g_free ( folder ) ;
}

gboolean explorer_addressbar_process_keypress_event ( GtkWidget * widget, GdkEventKey * event, Explorer * e )
{
	warn ( "%d", event -> keyval ) ;
	
	if ( event -> keyval == GDK_Return )
	{
		explorer_addressbar_activated ( widget, e ) ;
		return false ;
	}
	
	else
		return true ;
}

void explorer_fire_event ( Explorer * e )
{
	GTimeVal tv ;
	g_get_current_time ( & tv ) ;
	
	e -> timestamp = tv.tv_usec ;
}

GList * explorer_get_selected_files ( Explorer * e )
{
	GList * l1 = gtk_icon_view_get_selected_items ( e -> iconview ),
		  * list = null ;
	
	if ( l1 == null )
		return ;
	
	gint i = 0, len = g_list_length ( l1 ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		GtkTreeIter iter ;
		gtk_tree_model_get_iter ( e -> store, & iter, g_list_nth_data ( l1, i )) ;
		
		gchar * filename = null ;
		gtk_tree_model_get ( e -> store, & iter, 2, & filename, -1 ) ;
		
		list = g_list_append ( list, filename ) ;
	}
	
	g_list_foreach ( l1, gtk_tree_path_free, null ) ;
	g_list_free ( l1 ) ;
	
	return list ;
}

void explorer_copy_callback ( Explorer * e )
{
	explorer_set_status_message ( e, "Files copied to Clipboard" ) ;
	explorer_copy_to_clipboard ( e, COPY ) ;
}

void explorer_cut_callback ( Explorer * e )
{
	explorer_set_status_message ( e, "Files cut to Clipboard" ) ;
	explorer_copy_to_clipboard ( e, CUT ) ;
}

void explorer_copy_to_clipboard ( Explorer * e, ClipboardAction action )
{
	GList * list = explorer_get_selected_files ( e ) ;
	if ( list == null )
		return ;
	
	gint i = 0, len = g_list_length ( list ) ;
	GString * s = g_string_new ( null ) ;
	
	g_string_printf ( s, "%d", action ) ;
	
	for ( i = 0 ; i < len ; i ++ )
		g_string_append_printf ( s, ";%s", g_list_nth_data ( list, i )) ;
	
	gtk_clipboard_set_text ( e -> clipboard, s -> str, s -> len ) ;
	g_debug ( "Copied %s to clipboard.", s -> str ) ;
	
	g_string_free ( s, yes ) ;
	g_list_foreach ( list, g_free, null ) ;
	
	g_list_free ( list ) ;
}

void explorer_paste_from_clipboard_callback ( GtkClipboard * clipboard, gchar * text, Explorer * e )
{
	if ( text == null )
		return ;
	
	gchar ** vector = g_strsplit ( text, ";", -1 ) ;
	ClipboardAction action = atoi ( vector [0] ) ;
	
	g_debug ( "Action is %d", action ) ;
	switch ( action )
	{
		case CUT:
		case COPY:
		case PASTE:
			gtk_true () ;
			break ;
		default:
			g_critical ( "Unable to perform operation ! "
						 "Invalid clipboard action specified." ) ;
			
			g_strfreev ( vector ) ;
			return ;
	}

	if ( vector [1] == null )
	{
		g_message ( "No files to paste !" ) ;
		g_strfreev ( vector ) ;
		
		return ;
	}
	
	GList * list = null ;
	
	gint i = 1 ;
	while ( vector [i] != null )
	{
		list = g_list_append ( list, vector [i] ) ;
		
		g_debug ( "Files to paste: [%d] %s", i, vector [i] ) ;
		i ++ ;
	}
	
	gchar * dir = explorer_get_current_folder ( e ) ;
	xfer_xfer ( e, action, list, dir ) ;
	
	//g_list_foreach ( list, g_free, null ) ;
	g_strfreev ( vector ) ;
	g_list_free ( list ) ;
	
}

void explorer_paste_from_clipboard ( Explorer * e )
{
	g_debug ( "Attempting to paste ..." ) ;
	gtk_clipboard_request_text ( e -> clipboard, explorer_paste_from_clipboard_callback, e ) ;
}

GList * explorer_get_selected_files_recursive ( Explorer * e )
{
	GList * l1 = gtk_icon_view_get_selected_items ( e -> iconview ),
		  * list = null ;
	
	if ( l1 == null )
		return ;
	
	gint i = 0, len = g_list_length ( l1 ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		GtkTreeIter iter ;
		gtk_tree_model_get_iter ( e -> store, & iter, g_list_nth_data ( l1, i )) ;
		
		gchar * filename = null ;
		gtk_tree_model_get ( e -> store, & iter, 2, & filename, -1 ) ;
		
		list = g_list_append ( list, filename ) ;
	}
	
	g_list_foreach ( l1, gtk_tree_path_free, null ) ;
	g_list_free ( l1 ) ;
	
	return list ;
}

GList * traverse_through_directory ( GList * list, gchar * folder )
{
	GDir * dir = g_dir_open ( folder, 0, null ) ;
	if ( dir == null )
		return ;
	
	gchar * name = g_dir_read_name ( dir ) ;
	while ( name )
	{
		gchar * filename = g_build_filename ( folder, name, null ) ;
		list = g_list_append ( list, filename ) ;
		
		if ( g_file_test ( filename, G_FILE_TEST_IS_DIR ))
		{
			list = traverse_through_directory ( list, filename ) ;
		}
		
		name = g_dir_read_name ( dir ) ;
	}
	
	g_dir_close ( dir ) ;
	return list ;
}

void explorer_delete_selected_files ( Explorer * e )
{
	GList * list = explorer_get_selected_files_recursive ( e ) ;
	xfer_delete ( e, list ) ;
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;
}

void _open_with_fill_store_from_folder ( GtkTreeModel * model, gchar * folder )
{
	GDir * dir = g_dir_open ( folder, 0, null ) ;
	if ( dir == null )
		return ;
	
	gchar * name = g_dir_read_name ( dir ) ;
	while ( name )
	{
		gchar * filename = g_build_filename ( folder, name, null ) ;
		
		GtkTreeIter iter ;
		gtk_tree_store_append ( model, & iter, null ) ;
		
		gtk_tree_store_set ( model, & iter, 0, name, 1, filename, -1 ) ;
		g_free ( filename ) ;
		
		name = g_dir_read_name ( dir ) ;
	}
	
	g_dir_close ( dir ) ;
}

	

GtkTreeModel * _open_with_fill_store ( void )
{
	GtkListStore * store = gtk_tree_store_new ( 2, G_TYPE_STRING, G_TYPE_STRING ) ;
	
	/* Try the usual locations */
	_open_with_fill_store_from_folder ( store, "/usr/bin" ) ;
	_open_with_fill_store_from_folder ( store, "bin" ) ;
	
	_open_with_fill_store_from_folder ( store, "/usr/sbin" ) ;
	_open_with_fill_store_from_folder ( store, "/sbin" ) ;
	
	return store ;
}
	
void explorer_open_with ( Explorer * e )
{
	GList * list = explorer_get_selected_files ( e ) ;
	if ( list == null )
		return ;
	
	GtkDialog * dialog = gtk_dialog_new_with_buttons ( "Open with",
														null,
														GTK_DIALOG_MODAL,
														"Cancel",
														0,
														null ) ;
	GtkButton * open_with = gtk_dialog_add_button ( dialog, "Open with", 1 ) ;
	
	GtkCellView * view = gtk_tree_view_new () ;
	GtkTreeModel * store = _open_with_fill_store () ;
	
	GtkScrolledWindow * sw = gtk_scrolled_window_new ( null, null ) ;
	gtk_scrolled_window_set_policy ( sw, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ) ;
	
	gtk_tree_view_set_model ( view, store ) ;
	
	GtkCellRenderer * renderer = gtk_cell_renderer_text_new () ;
	GtkTreeViewColumn * col = gtk_tree_view_column_new_with_attributes ( "Programs",
									renderer,
									"text",
									0,
									null ) ;
	
	g_signal_connect_swapped ( view, "row-activated", gtk_button_clicked, open_with ) ;
	gtk_tree_view_append_column ( view, col ) ;
	
	GtkLabel * l = gtk_label_new ( "Choose program to open the files with:" ) ;
	gtk_label_set_line_wrap ( l, true ) ;
	
	GtkEntry * entry = gtk_entry_new () ;
	GtkCheckButton * always = gtk_check_button_new_with_label ( "Always use this program" ),
					* terminal = gtk_check_button_new_with_label ( "Run in terminal" ) ;
	
	GtkWidget * box = gtk_hbox_new ( no, 2 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, l, no, no, 5 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, gtk_hseparator_new (), no, no, 5 ) ;
	gtk_box_pack_start ( dialog -> vbox, sw, yes, yes, 2 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, gtk_hseparator_new (), no, no, 5 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, entry, no, no, 5 ) ;
	gtk_box_pack_start ( dialog -> vbox, box, no, no, 5 ) ;
	
	gtk_tree_view_set_headers_visible ( view, no ) ;
	gtk_container_add ( sw, view ) ;
	
	gtk_box_pack_start ( box, always, no, no, 2 ) ;
	gtk_box_pack_start ( box, terminal, no, no, 2 ) ;
	
	gtk_window_resize ( dialog, 320, 450 ) ;
	
	gtk_widget_show_all ( dialog ) ;
	if ( ! gtk_dialog_run ( dialog ))
	{
		gtk_widget_destroy ( dialog ) ;

		g_list_foreach ( list, g_free, null ) ;
		g_list_free ( list ) ;

		return ;
	}
	
	gchar * app = null, * app1 = gtk_entry_get_text ( entry ) ;
	if ( gtk_entry_get_text_length ( entry ))
		app = g_strdup ( app1 ) ;
	
	else
	{
		GtkTreeSelection * selection = gtk_tree_view_get_selection ( view ) ;
		GtkTreeIter iter ;
		
		if ( gtk_tree_selection_get_selected ( selection, null, & iter ))
		{
			gtk_tree_model_get ( store, & iter, 1, & app, -1 ) ;
		}
	}
	
	if ( app == null )
	{
		gtk_widget_destroy ( dialog ) ;

		g_list_foreach ( list, g_free, null ) ;
		g_list_free ( list ) ;

		return ;
	}
	
	GString * s = null ;
	
	if ( gtk_toggle_button_get_active ( terminal ))
	{
		s = g_string_new ( "xterm;-e;" ) ;
		g_string_append_printf ( s, app ) ;
	}
	
	else
		s = g_string_new ( app ) ;
	
	
	if ( gtk_toggle_button_get_active ( always ))
	{
		gchar * db = g_build_filename ( g_get_home_dir (), ".system", "mime.db", null ) ;
		april_key_file_set_string ( db, g_strrstr ( g_list_nth_data ( list, 0 ), "." ), "exec", app ) ;
		
		g_free ( db ) ;
	}
	
	gint i = 0, len = g_list_length ( list ) ;
	
	for ( i = 0 ; i < len ; i ++ )
		g_string_append_printf ( s, ";%s", g_list_nth_data ( list, i )) ;
	
	gchar ** vector = g_strsplit ( s -> str, ";", -1 ) ;
	GError * error = null ;
	
	g_spawn_async ( null, vector, null, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
					null, null, null, & error ) ;
	
	if ( error )
		g_warning ( error -> message ) ;
	
	g_string_free ( s, true ) ;
	g_strfreev ( vector ) ;
	
	g_free ( app ) ;
	gtk_widget_destroy ( dialog ) ;
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;
}

void _explorer_activate ( Explorer * e )
{
	GList * list = explorer_get_selected_files ( e ) ;
	mime_handler ( e, g_list_nth_data ( list, 0 )) ;
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;
}	


void explorer_send_to ( GtkWidget * widget, Sendto * sendto )
{
	GList * list = explorer_get_selected_files ( sendto -> e ) ;
	if ( list == null )
		return ;
	
	switch ( sendto -> target )
	{
		case SEND_TO_DESKTOP:
		{
			gchar * desktop = g_build_filename ( g_get_home_dir (), "Desktop", null ) ;
			xfer_xfer ( sendto -> e, COPY, list, desktop ) ;
			
			g_free ( desktop ) ;
			break ;
		}
		
		case SEND_TO_DOCUMENTS:
			xfer_xfer ( sendto -> e, COPY, list, g_get_home_dir ()) ;
			break ;
			
		default:
			break ;
	}
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;
	
	sendto_destroy ( sendto ) ;
}
		
void explorer_create_shortcut ( Explorer * e )
{
	GList * list = explorer_get_selected_files ( e ) ;
	if ( list == null )
		return ;
	
	gint i = 0, len = g_list_length ( list ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		gchar * path = g_list_nth_data ( list, i ) ;
		gchar * dirname = g_path_get_dirname ( path ) ;
		
		gchar * basename = g_path_get_basename ( path ) ;
		gchar * new_link = g_strdup_printf ( "%s/Link to %s", dirname, basename ) ;

		if ( symlink ( path, new_link ))
			g_warning ( "Cannot create shortcut for %s: %s", 
						path, strerror ( errno )) ;
		else
			fm_append_to_store ( e, new_link ) ;
		
		g_free ( new_link ) ;
		g_free ( dirname ) ;
		
		g_free ( basename ) ;
		
	}
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;
}

void explorer_rename ( Explorer * e )
{
	
	GList * list = explorer_get_selected_files ( e ) ;
	if ( list == null )
		return ;
	
	gchar * path = g_list_nth_data ( list, 0 ) ;
	
	GtkDialog * dialog = gtk_dialog_new_with_buttons ( "Rename",
														null,
														GTK_DIALOG_MODAL,
														"Cancel",
														0,
														null ) ;
	
	GtkButton * ok = gtk_dialog_add_button ( dialog, "Rename", 1 ) ;
	GtkLabel * l = gtk_label_new ( null ) ;
	
	gchar * basename = g_path_get_basename ( path ) ;
	gchar * m = g_markup_printf_escaped ( "Rename  <big>%s</big>  to:", basename ) ;
	
	gtk_label_set_markup ( l, m ) ;
	g_free ( m ) ;
	
	gtk_label_set_line_wrap ( l, on ) ;
	gtk_box_pack_start ( dialog -> vbox, l, no, no, 5 ) ;
	
	GtkEntry * entry = gtk_entry_new () ;
	gtk_box_pack_start ( dialog -> vbox, entry, no, no, 5 ) ;
	
	gtk_entry_set_text ( entry, basename ) ;
	g_signal_connect_swapped ( entry, "activate", gtk_button_clicked, ok ) ;

	gtk_widget_show_all ( dialog ) ;
	if ( ! gtk_dialog_run ( dialog ))
	{
		gtk_widget_destroy ( dialog ) ;
		g_free ( basename ) ;
		
		g_list_foreach ( list, g_free, null ) ;
		g_list_free ( list ) ;
		
		return ;
	}
	
	gchar * text = gtk_entry_get_text ( entry ) ;
	
	if ( gtk_entry_get_text_length ( entry ) && g_strcmp0 ( basename, text ) != 0 )
	{
		gchar * dirname = g_path_get_dirname ( path ) ;
		gchar * new_name = g_build_filename ( dirname, text, null ) ;
		
		if ( g_rename ( path, new_name ))
			g_critical ( "Cannot rename file! %s", strerror ( errno )) ;
		
		else
		{
			GtkTreeIter iter ;
			GList * ll = gtk_icon_view_get_selected_items ( e -> iconview ) ;
			
			gtk_tree_model_get_iter ( e -> store, & iter, g_list_nth_data ( ll, 0 )) ;
			gtk_list_store_set ( e -> store, & iter, 1, text, -1 ) ;
			
			g_list_foreach ( ll, gtk_tree_path_free, null ) ;
			g_list_free ( ll ) ;
		}				
		
		g_free ( dirname ) ;
		g_free ( new_name ) ;
	}
	
	gtk_widget_destroy ( dialog ) ;
	g_free ( basename ) ;
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;

	
}

void explorer_file_info ( Explorer * e )
{
	GList * list = explorer_get_selected_files ( e ) ;
	if ( list == null )
	{
		list = g_list_append ( list, explorer_get_current_folder ( e )) ;
	}
	
	GError * error = null ;
	
	gchar * path = g_list_nth_data ( list, 0 ) ;
	GFile * file = g_file_new_for_path ( path ) ;
	
	GFileInfo * info = g_file_query_info ( file, "*", G_FILE_QUERY_INFO_NONE, null, & error ) ;
	if ( error )
	{
		g_warning ( error -> message ) ;
		g_object_unref ( file ) ;
		
		g_object_unref ( info ) ;
		
		g_list_foreach ( list, g_free, null ) ;
		g_list_free ( list ) ;
		
		return ;
	}
	
	gchar ** attributes = g_file_info_list_attributes ( info, null ) ;
	gint i = 0 ;
	
	GString * s = g_string_new ( null ) ;
	
	while ( attributes [i] != null )
	{
		gchar * a = g_file_info_get_attribute_as_string ( info, attributes [i] ) ;
		g_string_append_printf ( s, "%s: %s\n", attributes [i], a ) ;
		
		g_free ( a ) ;
		i ++ ;
	}
	
	g_strfreev ( attributes ) ;
	gchar * basename = g_path_get_basename ( path ) ;
	
	prompt_detailed_info ( basename, s -> str ) ;
	g_string_free ( s, true ) ;
	
	g_object_unref ( file ) ;
	g_object_unref ( info ) ;
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;
	
	g_free ( basename ) ;
}	
	
	
void explorer_delete_from_clipboard_callback ( GtkClipboard * clipboard, gchar * text, Explorer * e )
{
	if ( text == null )
		return ;
	
	gchar ** vector = g_strsplit ( text, ";", -1 ) ;
	if ( vector [1] == null )
	{
		g_message ( "No files to delete !" ) ;
		g_strfreev ( vector ) ;
		
		return ;
	}
	
	GList * list = null ;
	
	gint i = 1 ;
	while ( vector [i] != null )
	{
		gchar * basename = g_path_get_basename ( vector [i] ) ;
		gchar * parent = explorer_get_current_folder ( e ) ;
		
		gchar * path = g_build_filename ( parent, basename, null ) ;
		list = g_list_append ( list, path ) ;
		
		g_free ( basename ) ;
		g_free ( parent ) ;
		
		g_debug ( "Files to delete: [%d] %s", i, path ) ;
		i ++ ;
	}
	
	xfer_delete ( e, list ) ;
	g_list_foreach ( list, g_free, null ) ;

	g_strfreev ( vector ) ;
	g_list_free ( list ) ;
	
}

void explorer_delete_from_clipboard ( Explorer * e )
{
	g_debug ( "Attempting to delete ..." ) ;
	gtk_clipboard_request_text ( e -> clipboard, explorer_delete_from_clipboard_callback, e ) ;
}

void _explorer_paste_shortcut ( GtkClipboard * clipboard, gchar * text, Explorer * e )
{
	if ( text == null )
		return ;
	
	gchar ** vector = g_strsplit ( text, ";", -1 ) ;
	if ( vector [1] == null )
	{
		g_message ( "No files to paste !" ) ;
		g_strfreev ( vector ) ;
		
		return ;
	}
	
	gint i = 1 ;
	while ( vector [i] != null )
	{
		gchar * path = vector [i] ;
		gchar * dirname = explorer_get_current_folder ( e ) ;
		
		gchar * basename = g_path_get_basename ( path ) ;
		gchar * new_link = g_strdup_printf ( "%s/Link to %s", dirname, basename ) ;
	
		g_debug ( "Creating shortcut %s", new_link ) ;

		if ( symlink ( path, new_link ))
			g_warning ( "Cannot create shortcut for %s: %s", 
						path, strerror ( errno )) ;
		else
			fm_append_to_store ( e, new_link ) ;
		
		g_free ( new_link ) ;
		g_free ( dirname ) ;
		
		g_free ( basename ) ;
		i ++ ;
	}
	
	g_strfreev ( vector ) ;
}

void explorer_paste_shortcut ( Explorer * e )
{
	g_debug ( "Attempting to paste shortcut ..." ) ;
	gtk_clipboard_request_text ( e -> clipboard, _explorer_paste_shortcut, e ) ;
}

void explorer_destroy ( Explorer * e )
{
	g_object_unref ( e -> history_back ) ;
	
	g_object_unref ( e -> history_forward ) ;
	g_mem_chunk_destroy ( e -> mem ) ;
	
	g_debug ( __func__ ) ;
}

gchar * explorer_get_current_file ( Explorer * e )
{
	GList * list = explorer_get_selected_files ( e ) ;
	gchar * file = g_strdup ( g_list_nth_data ( list, 0 )) ;
	
	g_list_foreach ( list, g_free, null ) ;
	g_list_free ( list ) ;

	return file ;
}
